package com.zh.demo.redislock.services.impl;

import com.zh.demo.redislock.services.RedisLockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class RedisLockServiceImpl implements RedisLockService {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public void GetRedisLock() {
        String key = "redis-lock";
        //加锁
        Boolean locked = stringRedisTemplate.opsForValue().setIfAbsent(key, "locked");
        if (locked){
            //加锁成功
            System.out.println("加锁成功");
            //处理业务逻辑
            int x = 1 + 1;
            System.out.println(x);
            //业务逻辑处理完，释放锁（删除redis中的key:‘redis-lock’）
            stringRedisTemplate.delete(key);
        }else {
            //加锁失败
            //休眠
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //重试
            GetRedisLock();
        }
    }

    @Override
    public void GetRedisLockTimeOut() {
        String key = "redis-lock";
        //加锁，并设置过期时间
        Boolean locked = stringRedisTemplate.opsForValue().setIfAbsent(key, "locked", 10, TimeUnit.SECONDS);
        if (locked){
            //加锁成功
            System.out.println("加锁成功");
            //设置锁过期时间，可以直接在setIfAbsent中设置
            stringRedisTemplate.expire(key, 15,TimeUnit.SECONDS);
            //处理业务逻辑
            try{
                int x = 1 + 1;
                System.out.println(x);
            }finally {
                //业务逻辑处理完，释放锁（删除redis中的key:‘redis-lock’）
                stringRedisTemplate.delete(key);
            }
        }else {
            //加锁失败
            //休眠
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //重试
            GetRedisLockTimeOut();
        }
    }

    @Override
    public void GetUniqueRedisLockTimeOut() {
        String key = "redis-lock";
        //获取锁唯一标识
        String uuid = UUID.randomUUID().toString();
        //加锁，并设置过期时间
        Boolean locked = stringRedisTemplate.opsForValue().setIfAbsent(key, uuid, 10, TimeUnit.SECONDS);
        if (locked){
            //加锁成功
            System.out.println("加锁成功");
            //设置锁过期时间，可以直接在setIfAbsent中设置
            stringRedisTemplate.expire(key, 15,TimeUnit.SECONDS);
            //处理业务逻辑
            try{
                int x = 1 + 1;
                System.out.println(x);
            }finally {
                //业务逻辑处理完，释放锁（删除redis中的key:‘redis-lock’）
                //重新获取锁的uuid判断是否一致
//                String lockValue = stringRedisTemplate.opsForValue().get(key);
//                if(uuid.equals(lockValue)){
//                    stringRedisTemplate.delete(key);
//                }
                String script = "if redis.call('get',KEYS[1]) == ARGV[1]  then return redis.call('del',KEYS[1]) else  return 0 end ";
                // 通过Redis的lua脚本实现 查询和删除操作的原子性
                stringRedisTemplate.execute(new DefaultRedisScript<Long>(script,Long.class)
                        , Arrays.asList(key),uuid);
            }
        }else {
            //加锁失败
            //休眠
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //重试
            GetRedisLockTimeOut();
        }
    }
}
